package crud.client.dialog;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.IButton;
import com.smartgwt.client.widgets.Label;
import com.smartgwt.client.widgets.Window;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.fields.FormItem;
import com.smartgwt.client.widgets.form.fields.FormItemIcon;
import com.smartgwt.client.widgets.form.validator.CustomValidator;
import com.smartgwt.client.widgets.form.validator.Validator;
import com.smartgwt.client.widgets.grid.ListGridRecord;

import crud.client.constant.CstTypeEdition;
import crud.client.data.Colonne;
import crud.client.data.Donnee;
import crud.client.data.LigneDonnee;
import crud.client.data.Table;
import crud.client.data.authentication.Right;
import crud.client.factory.validator.field.ValidatorFactory;
import crud.client.factory.validator.table.TableValidator;
import crud.client.factory.validator.table.TableValidatorFactory;

public class TableLine extends Window
{
	private Label label = new Label();
	private String typeEdition;
	private TableCRUD parentTableCRUD;
	private LigneDonnee ligneDonnee;
	private final List<TableValidator> tableValidatorList = new ArrayList<TableValidator>();


	private IButton cancelButton;
	private IButton saveButton;
	private DynamicForm dynamicForm = new DynamicForm();
	private String initialPk;

	public TableLine(final TableCRUD parentTableCRUD, String typeEdtion)
	{
		this(parentTableCRUD, new LigneDonnee(null, parentTableCRUD.getColonneList()), false, typeEdtion);
	}

	
	public TableLine(final TableCRUD parentTableCRUD, LigneDonnee ligneDonnee, boolean isDataUsed, String typeEdtion)
	{
		this.parentTableCRUD = parentTableCRUD;
		this.ligneDonnee = ligneDonnee;
		this.typeEdition = typeEdtion;
		this.initialPk = parentTableCRUD.extractPK(ligneDonnee);

		this.setTitle(parentTableCRUD.getTitle());
		this.setIsModal(true);
		this.setCanDragResize(true);
		this.setIsModal(true);

		Canvas canvas = new Canvas();
		canvas.setTop(30);
		canvas.setLeft(10);
		canvas.addChild(label);

		// Le formulaire et ses champs
		int height = 40;
		FormItem formItemTable[] = new FormItem[getColonneList().size()];
		for (int cp = 0; cp <= getColonneList().size() - 1; cp++)
		{
			Colonne colonne = getColonneList().get(cp);

			FormItem formItem = null;
			if (ligneDonnee != null)
			{
				formItem = colonne.getFormItemFactory().newFormItem(colonne, ligneDonnee.getDonnee(colonne));
			} else
			{
				formItem = colonne.getFormItemFactory().newFormItem(colonne, null);
			}

			// Les validateurs
			List<Validator> validatorList = colonne.getFormItemFactory().newValidatorList(colonne);
			
			// Autres validateurs (par annotation)
			for (ValidatorFactory validatorFactory : colonne.getValidatorFactoryList())
			{
				validatorList.add(validatorFactory.newValidator(colonne));
			}
			
			// Validateurs de table (par annotation)
			for (TableValidatorFactory validatorFactory : colonne.getTableValidatorFactoryList())
			{
				TableValidator validator = validatorFactory.newValidator(colonne);
				validatorList.add(validator);
				tableValidatorList.add(validator);
			}


			if (colonne.isPk())
			{
				FormItemIcon formItemIcon = new FormItemIcon();
				formItemIcon.setSrc("/img/pk.jpeg");
				formItem.setIcons(formItemIcon);

				if (colonne.isGeneratedValue() == false)
				{
					validatorList.add(new PkValidator());
				}

				formItem.setRequired(!colonne.isGeneratedValue());

				// Si la donnée est déjà utilisée dans une autre table, la clef primaire n'est pas modifiable
				if (isDataUsed == true)
				{
					formItem.setDisabled(true);
					formItem.setHint("<span style=\"color: green;\">" + "Donn&eacute;e&nbsp;est&nbsp;r&eacute;f&eacute;renc&eacute;e&nbsp;dans&nbsp;une&nbsp;autre&nbsp;table. Clef primaire non modifiable" + "</span><br/>");
					formItem.setWrapTitle(false);
				}
				// Si la donnée est une generatedvalue
				else if (colonne.isGeneratedValue() == true)
				{
					formItem.setDisabled(true);
					formItem.setHint("<span style=\"color: green;\">" + "Donn&eacute;e&nbsp;gérée par la base" + "</span><br/>");
					formItem.setWrapTitle(false);
				}
			}

			// toujours les validateurs
			formItem.setValidators(validatorList.toArray(new Validator[validatorList.size()]));

			formItemTable[cp] = formItem;

			try
			{
				height += formItem.getHeight();
			} catch (Exception e)
			{
				height += 20;
			}
		}

		dynamicForm.setItems(formItemTable);
		canvas.addChild(dynamicForm);
		canvas.setHeight(height + 60);

		// Bouton annuler
		cancelButton = new IButton("Annuler");
		cancelButton.addClickHandler(new ClickHandler()
		{
			public void onClick(ClickEvent event)
			{
				TableLine.this.hide();
			}
		});

		// Bouton valider
		saveButton = new IButton("Valider");
		saveButton.addClickHandler(new ClickHandler()
		{
			public void onClick(ClickEvent event)
			{
				setError("");
				
				// Les données saisies
				LigneDonnee ligneDonnee = TableLine.this.getLigneDonnee();
				
				// Populate de la liigne de donnée dans les validateurs de table
				for (TableValidator tableValidator : tableValidatorList)
				{
					tableValidator.setLigneDonnee(ligneDonnee);
				}
				
				// Validation des formulaires
				if (TableLine.this.isValid() == false)
				{
					return;
				}
				
				// Injection des données des formlaires dans la liste des données
				parentTableCRUD.addOrReplaceData(ligneDonnee, ligneDonnee.getLineNumber());

				TableLine.this.hide();
			}
		});

		// Position des éléments
		if (isDataUsed == false)
		{
			this.setWidth(350);
		} else
		{
			this.setWidth(550);
		}
		cancelButton.setLeft(10);
		saveButton.setLeft(this.getWidth() - 130);
		label.setLeft(140);

		int buttonTop = canvas.getTop() + height - 20;
		cancelButton.setTop(buttonTop);
		saveButton.setTop(buttonTop);
		label.setTop(buttonTop);

		canvas.addChild(cancelButton);
		
		canvas.addChild(saveButton);
		this.addChild(canvas);
		this.setHeight(canvas.getHeight() +  canvas.getTop() - 10);
		this.draw();

	}

	private boolean isValid()
	{
		return this.dynamicForm.validate();
	}

	private boolean isNouveau()
	{
		return this.typeEdition.equals(CstTypeEdition.NOUVEAU);
	}

	// private boolean isVisualisation()
	// {
	// return this.typeEdition.equals(CstTypeEdition.VISUALISATION);
	// }

	public class PkValidator extends CustomValidator
	{
		@Override
		protected boolean condition(Object value)
		{
			LigneDonnee ligneDonnee = getLigneDonnee();
			ListGridRecord existingRecord = parentTableCRUD.getCorrespondingRecord(ligneDonnee);

			if (existingRecord == null)
			{
				return true;
			}

			// Test d'unicité pour la création
			if (TableLine.this.isNouveau() == true)
			{
				this.setErrorMessage("Une meme chef primaire existe d&eacute;j&agrave;");
				return false;
			}

			// Test d'unicité pour la mise à jour
			String currentPk = TableLine.this.parentTableCRUD.extractPK(ligneDonnee);
			if (TableLine.this.initialPk.equals(currentPk) == false)
			{
				this.setErrorMessage("Une meme chef primaire existe d&eacute;j&agrave;");
				return false;
			}

			return true;
		}
	}

	public Table getTable()
	{
		return parentTableCRUD.getTable();
	}

	public List<Colonne> getColonneList()
	{
		return parentTableCRUD.getColonneList();
	}

	public List<Colonne> getPkList()
	{
		return parentTableCRUD.getPkList();
	}

	public List<Colonne> getNonPkList()
	{
		return parentTableCRUD.getNonPkList();

	}

	public LigneDonnee getLigneDonnee()
	{
		for (int cpFormItem = 0; cpFormItem <= getColonneList().size() - 1; cpFormItem++)
		{
			Colonne colonne = getColonneList().get(cpFormItem);
			final Donnee donnee = ligneDonnee.getDonnee(colonne);

			donnee.getDataView().setLabel(dynamicForm.getFields()[cpFormItem].getDisplayValue());
			Serializable value = (Serializable) dynamicForm.getFields()[cpFormItem].getValue();
			donnee.getDataView().setData(colonne.getFormItemFactory().getData(value));
			
			// ATTENTION ERREUR SI CHAMP NUMERIQUE !!!
			// FIXME
					if (value != null)
					{
						donnee.getDataView().setKey(value.toString());
					}
		}

		return ligneDonnee;
	}
	
	public void setError(String informationText)
	{
		label.setContents("<div style=\"color: red;\">" + informationText + "</div><br/>");
	}

}